// https://thebookofshaders.com/06/?lan=ch
import { 
  Camera,  
  Color,  
  Mesh, 
  PlaneBufferGeometry, 
  Scene, 
  ShaderMaterial, 
  Vector3, 
  WebGLRenderer 
} from "three"

const canvas = document.createElement('canvas')
document.body.appendChild(canvas)
canvas.style.width = '100vw'
canvas.style.height = '100vh'

const scene = new Scene()
const renderer = new WebGLRenderer({
  antialias: true,
  canvas
})
renderer.autoClearColor = false

const camera = new Camera()
camera.position.z = 1
const plane = new PlaneBufferGeometry(2, 3)

// 片段着色器
const fragmentShader = `
#include <common>

uniform vec2 u_resolution;
uniform float u_time;

#define TWO_PI 6.28318530718

vec3 rgb2hsb(in vec3 c) {
  vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
  vec4 p = mix(
    vec4(c.bg, K.wz), 
    vec4(c.gb, K.xy), 
    step(c.b, c.g)
  );
  vec4 q = mix(
    vec4(p.xyw, c.r),
    vec4(c.r, p.yzx),
    step(p.x, c.t)
  );
  float d = q.x - min(q.w, q.y);
  float e = 1.0e-10;

  return vec3(
    abs(q.z + (q.w - q.y) / (6.0 * d + e)),
    d / (q.x + e),
    q.x
  );
}

// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb(in vec3 c) {
  vec3 rgb = clamp(
    abs(
      mod(c.x*6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0
    ) -1.0, 
    0.0, 
    1.0
  );

  rgb = rgb * rgb * (3.0 - 2.0 * rgb);
  return c.z * mix(vec3(1.0), rgb, c.y);
}

void main() {
  vec2 st = gl_FragCoord.xy / u_resolution;
  vec3 color = vec3(0.0);

  // 效果1 平铺效果 
  // we map x (0.0 - 1.0) to the hue (0.0 - 1.0)
  // and the y (0.0 - 1.0) to the brightness
  // color = hsb2rgb(vec3(st.x, 1.0, st.y));

  // 效果2 中心放射效果
  // 返回值映射到0.0到1.0
  vec2 toCenter = vec2(0.5) - st;
  // atan(y,x) 会返回一个介于-PI到PI的弧度值（-3.14 to 3.14）
  float angle = atan(toCenter.y, toCenter.x);
  // 半径会返回一个最大值0.5（因为我们计算的是到视口中心的距离，而视口中心的范围已经被映射到0.0到1.0）
  // 所以我们需要把这个值乘以二来得到一个0到1.0的映射。
  float radius = length(toCenter)*2.0;

  // Map the angle (-PI to PI) to the Hue (from 0 to 1)
  // and the Saturation to the radius
  // 所以我们要将这个返回值除以 TWO_PI（在code顶部定义了）来得到一个-0.5到0.5的值
  color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0));

  gl_FragColor = vec4(color, 1.0);
}
`

// const material = new MeshBasicMaterial({ color: 'red' })
const uniforms = {
  u_time: { value: 0 },
  u_resolution: { value: new Vector3() },
}
const material = new ShaderMaterial({
  fragmentShader,
  uniforms
})
scene.add(new Mesh(plane, material))

function render(time) {
  // 转化成秒
  time *= 0.001

  uniforms.u_time.value = time
  const canvas = renderer.domElement
  uniforms.u_resolution.value.set(canvas.width, canvas.height, 1)

  renderer.render(scene, camera)

  requestAnimationFrame(render)
}

requestAnimationFrame(render)